/* 
 * File:   BodyFactoryDynamic.cpp
 * Author: mauro
 * 
 * Created on 6 de septiembre de 2014, 21:25
 */

#include "BodyFactoryDynamic.h"

BodyFactoryDynamic::BodyFactoryDynamic() {
}

BodyFactoryDynamic::BodyFactoryDynamic(b2World &world) {
    this->world = &world;
}

b2Body* BodyFactoryDynamic::getCharacter(b2Vec2 *pos, b2Vec2 *size) {

//    b2FixtureDef *fixtureDef = new b2FixtureDef;
    b2FixtureDef fixtureDef;
    
//    fixtureDef.filter.categoryBits = 0x0002;
//    fixtureDef.filter.maskBits = 0x0001;
//    fixtureDef.filter.groupIndex = -10;
    
    //    b2BodyDef *bodyDef = new b2BodyDef;
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(pos->x, pos->y);
    bodyDef.fixedRotation = true;
    b2Body *body = this->world->CreateBody(&bodyDef);
    b2Vec2 points[4];
    int x, y;

//    b2PolygonShape *box = new b2PolygonShape;
    b2PolygonShape box; 
    box.SetAsBox(size->x, size->y);

    fixtureDef.shape = &box;
    fixtureDef.density = 5.0f;
    fixtureDef.friction = FRICTION;
    body->CreateFixture(&fixtureDef);
    
//    b2FixtureDef* footFixt = new b2FixtureDef;
    b2FixtureDef footFixt;
//    footFixt.filter.categoryBits = 0x0002;
//    footFixt.filter.maskBits = 0x0001;
//    b2PolygonShape* footPoly = new b2PolygonShape;
    b2PolygonShape footPoly;

    footFixt.isSensor = true;
    float sensorW = (90 * size->x)/100;
    float sensorH = (1 * size->y)/100;
    
    footPoly.SetAsBox(sensorW,sensorH,b2Vec2(0,size->y),0);
    footFixt.shape = &footPoly;
    body->CreateFixture(&footFixt);
    
    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se creo al personaje en el mundo\n");        
        
    return body;
}

b2Body* BodyFactoryDynamic::getBody(int sides, b2Vec2 *pos, b2Vec2 *size, float scale, float mass,float rotation) {
    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);

    if (sides == 1 || sides == 2){
        myLogFile->writeInLog(0, "[0] La cantidad de lados es mayor a 0 y menor a 3, se creara un circulo por defecto\n");        
    } else if (sides > 6){
        myLogFile->writeInLog(0, "[0] La cantidad de lados es mayor a 6, se creara un hexagono por defecto\n");            
    }

    //Fixture    
    b2FixtureDef fixtureDef;
    fixtureDef.userData = (void*)IS_FLOOR;
    fixtureDef.filter.categoryBits = 0x0003;    // obj dinamico
    fixtureDef.filter.maskBits = 0x0001 | 0x0002 | 0x0003;        // obj cinematico y obj dinamico
    //Definicion
    b2BodyDef bodyDef;
    //tipo
    bodyDef.type = b2_dynamicBody;

    //poss
    bodyDef.position.Set(pos->x, pos->y);
    //Creo un cuerpo     
    bodyDef.angle = rotation;
    b2Body *body = this->world->CreateBody(&bodyDef);
    //Points
    b2Vec2 points[sides];
    //coooooooordenadas
    int x, y;

    //Circulo = 0    
    if (sides < 3) {
        b2CircleShape circle;
        //creo un circulo.
        circle.m_radius = scale;
    
        fixtureDef.shape = &circle;
        // Set the box density to be non-zero, so it will be dynamic.
        fixtureDef.density = mass / (scale * (M_PI/2));
        // Override the default friction.
        fixtureDef.friction = FRICTION;
        //finalizo la creacion del rectangulo
//                fixtureDef.restitution = 1.0f;
        body->CreateFixture(&fixtureDef);
    
        myLogFile->writeInLog(0, "[0] Se ha creado un circulo dinamico en el mundo\n");
        
        return body;
    }

    if (sides == 4) {

        b2PolygonShape box ;

        //b2Vec2 *vel = new b2Vec2(10.0f,-12.0f);
        //body->SetLinearVelocity(*vel);
        //creo un rectangulo
        box.SetAsBox(size->x, size->y);


        fixtureDef.shape = &box;
        //Set the box density to be non-zero, so it will be dynamic.
        fixtureDef.density = mass / (size->x * size->y);
        //Override the default friction.
        fixtureDef.friction = FRICTION;
//                fixtureDef.restitution = 1.0f;
        //finalizo la creacion del rectangulo
        body->CreateFixture(&fixtureDef);        

        myLogFile->writeInLog(0, "[0] Se ha creado un poligono dinamico en el mundo de 4 lados\n"); 
        
        return body;
    }

    if (sides >= 5 || sides == 3) {

        if(sides > 6){
            sides = 6;
        }

        b2PolygonShape poly;
        float side = ((2 * scale) * sin(M_PI / sides));
        float x, y;
        int k;
        for (k = 0; k < sides; k++) {
            x = side * cos(2 * M_PI * k / sides);
            y = side * sin(2 * M_PI * k / sides);
            points[k].Set(x, y);
        }
        poly.Set(points, sides);

        fixtureDef.shape = &poly;
        //Set the box density to be non-zero, so it will be dynamic.
        float area = 0.5 * sides * side * sqrt(pow(scale,2) - pow((side/2),2));
        if (area < 0){
            area = area * (-1);
        } else if (area == 0){
            area = 1;
        }

        fixtureDef.density = mass / area;
        //Override the default friction.
        fixtureDef.friction = FRICTION;
        //finalizo la creacion del rectangulo
        body->CreateFixture(&fixtureDef);

        myLogFile->writeInLog(0, "[0] Se ha creado un poligono estatico en el mundo de "); 
        myLogFile->writeInLog(0, to_string(sides));
        myLogFile->writeInLog(0," lados\n");
                
        return body;
    }

    myLogFile->writeInLog(2, "[2] No se encontro una figura valida con la cantidad de lados solicitado\n");            
    
    return NULL;
}

b2Body* BodyFactoryDynamic::getBodyParallellogram(b2Vec2* pos, b2Vec2* size, float alpha, float mass, float rotation){

    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(pos->x, pos->y);
    bodyDef.angle = rotation;
    b2Body* body = this->world->CreateBody(&bodyDef);
    
    
    b2FixtureDef fixtDef;
    fixtDef.userData = (void*)IS_FLOOR;
    b2PolygonShape parall;
    
    float side = (size->y)/sin(alpha) * 2;
    float ady = cos(alpha)*side;    
    
    b2Vec2 points[4];           // paralelogramo = 4 lados

    points[0].Set(ady - (size->x), (-1)*(size->y));
    points[1].Set(ady + (size->x), (-1)*(size->y));
    points[2].Set((size->x), (size->y));
    points[3].Set((-1)*(size->x), (size->y));

    parall.Set(points,4);
    fixtDef.shape = &parall;
    fixtDef.density = mass / (size->x * size->y);
    fixtDef.friction = FRICTION;
    
    body->CreateFixture(&fixtDef);

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se ha creado un paralelogramo dinamico en el mundo\n");    
    
    return body;
}


b2Body* BodyFactoryDynamic::getBodyTrapezium(b2Vec2* pos, b2Vec2* size, float alpha, float beta, float mass, float rotation){

    if (alpha == 90 || alpha == 180 || alpha == 0 || alpha == 270){
        SBSLog* myLogFile;
        myLogFile->getInstance(MY_LOG_MODE);
        myLogFile->writeInLog(2, "[2] La relacion con el angulo ALPHA del trapecio no es valido\n");    
    } 
    if (beta == 90 || beta == 180 || beta == 0 || beta == 270){
        SBSLog* myLogFile;
        myLogFile->getInstance(MY_LOG_MODE);
        myLogFile->writeInLog(2, "[2] La relacion con el angulo BETA del trapecio no es valido\n");    

    }
    
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(pos->x, pos->y);
    bodyDef.angle = rotation;
    b2Body* body = this->world->CreateBody(&bodyDef);
   
    b2FixtureDef fixtDef;
    fixtDef.userData = (void*)IS_FLOOR;

    b2PolygonShape trap; 
   
    float adyAlpha = size->y * cos(alpha)/sin(alpha) * 2;
    float adyBeta = size->y * cos(beta)/sin(beta) * 2;

    b2Vec2 points[4];
    points[0].Set((-1) * size->x, size->y);
    points[1].Set(size->x, size->y);
    points[2].Set(size->x - adyBeta, (-1) * size->y);
    points[3].Set(adyAlpha - size->x, (-1) * size->y);

    trap.Set(points,4);
    fixtDef.shape = &trap;
   
    float area = (2 * size->x - adyAlpha - adyBeta) * size->y * (1/2);
    if (area < 0){
        area = area * (-1);
    } else if (area == 0){
        area = 1;
    }
   
    fixtDef.density = mass / area;
    fixtDef.friction = FRICTION;
   
    body->CreateFixture(&fixtDef);

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se ha creado un trapecio dinamico en el mundo\n");
   
    return body;

}
//
//b2Body* BodyFactoryDynamic::getBodyTrapezium(b2Vec2* pos, b2Vec2* size, float alpha, float beta, float mass, float rotation){
//
//    if (alpha == 90 || alpha == 180 || alpha == 0 || alpha == 270){
//        alpha = alpha + 5;
//    } 
//    if (beta == 90 || beta == 180 || beta == 0 || beta == 270){
//        beta = beta + 5;
//    }
//    
//    b2BodyDef* bodyDef = new b2BodyDef;
//    bodyDef->type = b2_dynamicBody;
//    bodyDef->position.Set(pos->x, pos->y);
//    bodyDef->angle = rotation;
//    b2Body* body = this->world->CreateBody(bodyDef);
//    
//    b2FixtureDef* fixtDef = new b2FixtureDef;
//    fixtDef->userData = (void*)IS_FLOOR;
//
//    b2PolygonShape* trap = new b2PolygonShape;
//    
//    float adyAlpha = size->y * cos(alpha) / sin(alpha) * 2;
//    float adyBeta = size->y * cos(beta) / sin(beta) * 2;
//
//    b2Vec2 points[4];
//    points[0].Set((-1) * size->x, size->y);
//    points[1].Set(size->x, size->y);
//    points[2].Set(size->x - adyBeta, (-1) * size->y);
//    points[3].Set(adyAlpha - size->x, (-1) * size->y);
//
//    trap->Set(points,4);
//    fixtDef->shape = trap;
//    
//    float area = (2 * size->x - adyAlpha - adyBeta) * size->y * (1/2);
//    if (area < 0){
//        area = area * (-1);
//    } else if (area == 0){
//        area = 1;
//    }
//    
//    fixtDef->density = mass / area;
//    fixtDef->friction = FRICTION;
//    
//    body->CreateFixture(fixtDef);
//
//    SBSLog* myLogFile;
//    myLogFile->getInstance(MY_LOG_MODE);
//    myLogFile->writeInLog(0, "Se ha creado un trapecio dinamico en el mundo\n");
//    
//    return body;
//
//}

BodyFactoryDynamic::~BodyFactoryDynamic() {
//    printf("destructor dynamic");
}

